﻿using CppAst;

namespace ast;

class Program
{
    static void Main(string[] args)
    {
        var options = new CppParserOptions()
        {
            // Pass the defines -DMYDEFINE to the C++ parser
            Defines =
            {
                "B3_USE_DOUBLE_PRECISION=1",
                "BT_USE_DOUBLE_PRECISION=1",
                "DT_VIRTUAL_QUERYFILTER=1",
                "ASSIMP_BUILD_NO_C4D_IMPORTER",
                "ASSIMP_BUILD_NO_M3D_EXPORTER",
                "ASSIMP_BUILD_NO_M3D_IMPORTER",
                "ASSIMP_BUILD_NO_OWN_ZLIB",
                "MINIZ_USE_UNALIGNED_LOADS_AND_STORES=0",
                "OPENDDLPARSER_BUILD",
                "OPENDDL_STATIC_LIBARY",
                "RAPIDJSON_HAS_STDSTRING=1",
                "RAPIDJSON_NOMEMBERITERATORCLASS",
                "NDEBUG",
                "PX_PHYSX_STATIC_LIB",
                "PX_PUBLIC_RELEASE=0",
                // "PX_SIMD_DISABLED",
                "PX_SUPPORT_OMNI_PVD=0",
                "PX_SUPPORT_PVD=0",
            }
        };
        // var outDir = "./out";
        // var moduleDir = "./include/test";
        // var moduleName = "test";

        // var moduleName = "bullet";
        // var outDir = "/Users/zheng/hasika/bullet-go/bullet";
        // var moduleDir = "/Users/zheng/hasika/bullet-go/include";

        // var moduleName = "bullet";
        // var moduleDir = "C:\\code\\go\\hasika\\bullet-go\\include";
        // var outDir = "C:\\code\\go\\hasika\\bullet-go\\bullet";
        // var outDir = "C:\\code\\c++\\bullet3\\src\\GoWrap\\src";


        // var moduleName = "assimp";
        // var moduleDir = "C:\\code\\go\\hasika\\model\\include";
        // var outDir = "C:\\code\\go\\hasika\\model\\assimp";
        // var outDir = "C:\\code\\c++\\assimp\\GoWrap\\src";
        // options.IncludeFolders.Add("C:\\code\\c++\\assimp\\contrib\\pugixml\\src");

        // var moduleName = "assimp";
        // var moduleDir = "/Users/zheng/hasika/model/include";
        // var outDir = "/Users/zheng/hasika/model/assimp";
        // options.IncludeFolders.Add("/Users/zheng/c++/assimp/contrib/pugixml/src");
        // options.IncludeFolders.Add("/Users/zheng/c++/assimp/contrib/zlib");

        var moduleName = "nav";
        // var outDir = "C:\\code\\go\\hasika\\navigation\\nav";
        var outDir = "./out";
        var moduleDir = "C:\\code\\go\\hasika\\navigation\\include\\recastnavigation";

        // var moduleName = "nav";
        // var outDir = "./out";
        // var moduleDir = "/Users/zheng/hasika/navigation/include/recastnavigation";

        // var moduleName = "physx";
        // var moduleDir = "/Users/zheng/hasika/physx-go/include";
        // var outDir = "/Users/zheng/hasika/physx-go/physx";
        // var outDir = "/Users/zheng/c++/PhysX/physx/source/wrap/src";

        // var moduleName = "physx";
        // var moduleDir = "C:\\code\\go\\hasika\\physx-go\\include";
        // var outDir = "C:\\code\\go\\hasika\\physx-go\\physx";
        // var outDir = "C:\\code\\c++\\PhysX\\physx\\source\\wrap\\src";


        moduleDir = Path.GetFullPath(moduleDir);
        outDir = Path.GetFullPath(outDir);


        options.IncludeFolders.Add(moduleDir);

        InitDarwin(options);

        var extraFileInclude = new SortedDictionary<string, List<string>>();
        extraFileInclude.Add("assimp/vector2.h", new List<string>(new[]
        {
            "assimp/vector2.inl",
        }));
        extraFileInclude.Add("assimp/vector3.h", new List<string>(new[]
        {
            "assimp/vector3.inl",
        }));
        extraFileInclude.Add("assimp/quaternion.h", new List<string>(new[]
        {
            "assimp/quaternion.inl",
            "assimp/matrix3x3.h",
            "assimp/matrix3x3.inl",
            "assimp/matrix4x4.h",
            "assimp/matrix4x4.inl",
        }));
        extraFileInclude.Add("assimp/color4.h", new List<string>(new[]
        {
            "assimp/color4.inl",
        }));
        extraFileInclude.Add("assimp/material.h", new List<string>(new[]
        {
            "assimp/material.inl",
        }));
        extraFileInclude.Add("assimp/matrix3x3.h", new List<string>(new[]
        {
            "assimp/matrix3x3.inl",
            "assimp/matrix4x4.h",
            "assimp/matrix4x4.inl",
            "assimp/vector2.h",
            "assimp/vector2.inl",
            "assimp/vector3.h",
            "assimp/vector3.inl",
        }));
        extraFileInclude.Add("assimp/matrix4x4.h", new List<string>(new[]
        {
            "assimp/matrix4x4.inl",
            "assimp/matrix3x3.h",
            "assimp/matrix3x3.inl",
            "assimp/quaternion.h",
            "assimp/quaternion.inl",
        }));

        extraFileInclude.Add("foundation/PxTransform.h", new List<string>(new[]
        {
            "foundation/PxMat44.h",
        }));
        extraFileInclude.Add("foundation/PxQuat.h", new List<string>(new[]
        {
            "foundation/PxMat33.h",
        }));
        var usePlatformFile = true;
        var compilation = CompileDir(options, moduleDir);
        var moduleinfo = new ModuleInfo(moduleName, moduleDir, compilation, extraFileInclude, usePlatformFile);
        var expot = new ExportConfig(moduleinfo, outDir,BuildTarget.Ts);
        expot.Run();
    }

    private static void InitDarwin(CppParserOptions options)
    {
        if (!OperatingSystem.IsMacOS())
        {
            if (OperatingSystem.IsWindows())
            {
                options.AdditionalArguments.Add("--target=x86_64-w64-windows-gnu");
                options.SystemIncludeFolders.Add("C:\\msys64\\clang64\\include\\c++\\v1");
                options.SystemIncludeFolders.Add("C:\\msys64\\clang64\\include");
                options.SystemIncludeFolders.Add("C:\\msys64\\clang64\\lib\\clang\\18\\include");
            }

            return;
        }

        options.IncludeFolders.Add("/usr/local/include");
        options.TargetSystem = "darwin";
        options.TargetCpu = CppTargetCpu.ARM64;
        options.SystemIncludeFolders.Add(
            "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk");
        options.SystemIncludeFolders.Add(
            "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1");
        options.SystemIncludeFolders.Add(
            "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include");
        options.SystemIncludeFolders.Add(
            "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include");
        options.SystemIncludeFolders.Add(
            "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include");
    }

    private static CppCompilation CompileDir(CppParserOptions options,
        string moduleDir)
    {
        var allFiles = new List<string>();
        FileVisitor(moduleDir, path =>
        {
            if (!path.EndsWith(".h") && !path.EndsWith(".hpp") && !path.EndsWith(".inl"))
            {
                return;
            }

            allFiles.Add(path);
        });
        var compilation = CppParser.ParseFiles(moduleDir, allFiles, options);
        if (compilation.HasErrors)
        {
            Console.WriteLine(compilation.Diagnostics.ToString());
            throw new Exception(compilation.Diagnostics.ToString());
        }

        return compilation;
    }

    delegate void Visitor(string path);

    static void FileVisitor(string path, Visitor func)
    {
        var isFile = File.Exists(path);
        var isDir = Directory.Exists(path);
        if (isFile && !isDir)
        {
            func(path);
            return;
        }

        if (isDir)
        {
            var allFiles = Directory.GetFiles(path);
            var dirs = Directory.GetDirectories(path);
            foreach (var oneFile in allFiles)
            {
                FileVisitor(oneFile, func);
            }

            foreach (var oneFile in dirs)
            {
                FileVisitor(oneFile, func);
            }
        }
    }
}